import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.StringTokenizer;

/*
 * 基于Socket的POP邮件接收客户端
 */
public class POPClient {
    private Socket socket = null;

    public POPClient(String server, int port) throws UnknownHostException, IOException {
        try {
            // 创建socket连接
            socket = new Socket(server, port);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("Connection established!");
        }
    }

    public String getReturn(BufferedReader in) {
        String line = "";
        try {
            // 从流中获取响应信息存入字符串
            line = in.readLine();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return line;
    }

    public String getResult(String line) {
        // 利用分词工具将响应信息分割
        StringTokenizer stringTokenizer = new StringTokenizer(line, " ");
        return stringTokenizer.nextToken();
    }

    public String sendCommand(String str, BufferedReader in, BufferedWriter out) throws IOException {
        // 将字符串写入流
        out.write(str);
        // 换行
        out.newLine();
        // 清空缓冲区
        out.flush();
        return getReturn(in);
    }

    public void user(String user, BufferedReader in, BufferedWriter out) throws IOException {
        String result = null;
        result = getResult(getReturn(in));
        // 判断是否与POP服务器建立连接
        if (!result.equals("+OK")) {
            throw new IOException("Connection failed!");
        }
        // 获取发送user指令后的响应状态
        result = getResult(sendCommand("user " + user, in, out));
        if (!result.equals("+OK")) {
            throw new IOException("Wrong username!");
        }
    }

    public void pass(String password, BufferedReader in, BufferedWriter out) throws IOException {
        String result = null;
        // 获取发送pass指令后的响应状态
        result = getResult(sendCommand("pass " + password, in, out));
        if (!result.equals("+OK")) {
            throw new IOException("Wrong password!");
        }
    }

    public void stat(BufferedReader in, BufferedWriter out) throws IOException {
        String result = null;
        String line = null;
        int mailNum = 0;
        line = sendCommand("stat", in, out);
        // 返回信息分词
        StringTokenizer stringTokenizer = new StringTokenizer(line, " ");
        // 状态信息
        result = stringTokenizer.nextToken();
        if (stringTokenizer.hasMoreTokens()) {
            // 邮件数量信息
            mailNum = Integer.parseInt(stringTokenizer.nextToken());
        }
        if (!result.equals("+OK")) {
            throw new IOException("Wrong stat check!");
        }
        // 输出邮件数量
        System.out.println("There are " + mailNum + " mails.");
    }

    public void list(BufferedReader in, BufferedWriter out) throws IOException {
        StringBuilder message = new StringBuilder();
        String line = null;
        line = sendCommand("list", in, out);
        while (!line.equalsIgnoreCase(".")) {
            message.append(line).append("\n");
            line = in.readLine().toString();
        }
        System.out.println(message);
    }

    public String getMessageDetail(BufferedReader in) throws UnsupportedEncodingException {
        StringBuilder message = new StringBuilder();
        String line = null;
        try {
            // 将每行邮件内容读取出来并存放至message中
            line = in.readLine().toString();
            while (!line.equalsIgnoreCase(".")) {
                message.append(line).append("\n");
                line = in.readLine().toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return message.toString();
    }

    public void retr(int mailNum, BufferedReader in, BufferedWriter out) throws IOException, InterruptedException {
        String result = null;
        // 获取发送retr指令后的响应状态
        result = getResult(sendCommand("retr " + mailNum, in, out));
        if (!result.equals("+OK")) {
            throw new IOException("Failed to receive mail!");
        }
        // 解析并输出邮件内容
        System.out.println("Mail No." + mailNum);
        System.out.println(getMessageDetail(in));
        Thread.sleep(3000);
    }

    public void quit(BufferedReader in, BufferedWriter out) throws IOException {
        String result = null;
        // 获取发送quit指令后的响应状态
        result = getResult(sendCommand("QUIT", in, out));
        if (!result.equals("+OK")) {
            throw new IOException("Failed to quit!");
        }
    }

    public void receiveMail(String user, String password) {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            user(user, in, out);
            pass(password, in, out);
            stat(in, out);
            list(in, out);
            retr(1, in, out);
            quit(in, out);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws UnknownHostException, IOException {
        String server = "pop3.163.com";
        String username = "m13337046103@163.com";
        String password = "ch78661697300000";
        POPClient popClient = new POPClient(server, 110);
        popClient.receiveMail(username, password);
    }
}
